package com.longyb.mylive.client;

import ch.qos.logback.core.net.server.Client;
import cn.hutool.core.util.HexUtil;
import com.alibaba.fastjson2.JSON;
import com.longyb.mylive.amf.Amf0Object;
import com.longyb.mylive.server.rtmp.Constants;
import com.longyb.mylive.server.rtmp.Tools;
import com.longyb.mylive.server.rtmp.messages.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *      三种包头，三种chunk
 *      四种指令  cmd, controller, meta,media
 *      * 推流的流程
 *      * 连接流程
 *     C->S connect
 *     S->C Wind Ack Size
 *     S->C bandwith per conn
 *     C->S Wind Ack Size
 *     S->C Stream begin
 *     S->C _Result
 *     创建流
 *     C->S releaseStream
 *     C->S FCPublish
 *     C->S createStream
 *     S->C stream Id
 *
 *     #推流
 *     C->S push 命令用上面的 StreamId
 *     S->C user controler stream begin
 *     C->S set chunk size
 *     S->C onStatus
 *     C->S meta data
 *     C->S audio ,video数据
 *     S->C 特定长度后ACK
 *
 *
 *     #拉流
 *      C->S play命令
 *      S->C set chunk size
 *      S->C user controler record 是否记录
 *      S->C stream begin
 *      S->C onState reset
 *      S->C onState start
 *      S->C audio ,video数据
 *
 *      参考： Monibuca 中的内存复用 https://cloud.tencent.com/developer/article/2343261
 *
 */
@Slf4j
public class RtmpClientHandler extends SimpleChannelInboundHandler<RtmpMessage> {

    private transient int status= ClientHandStatus.VERSION_RANDOM;

    private static Map<Integer,RtmpMsgHandler> statelessHandler=new HashMap<>();

    /**
     * 注册lambda函数，方式一
     */
    static {
        //
        statelessHandler.put(Constants.MSG_WINDOW_ACKNOWLEDGEMENT_SIZE,
          (RtmpMsgHandler<SetPeerBandwidth>) msg -> {

            return null;
          })  ;
    }
    /**
     * 注册处理器
     *
     /**
     * 注册lambda函数，方式二
     * @param msgId
     * @param handler
     */

    public static void registerStatelessHandler(Integer msgId,RtmpMsgHandler handler){
        synchronized (statelessHandler){
            if(statelessHandler.containsKey(msgId)){
                log.warn("msgId:{} 已经注册",msgId);
                return;
            }
            statelessHandler.put(msgId,handler);
        }

    }
    /**
     * https://blog.csdn.net/qq_41839588/article/details/134252460
     *  connect() ->createStream()
     * @param channelHandlerContext
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, RtmpMessage msg) throws Exception {
        Integer msgType=msg.getMsgType();
        log.info("客户端收到消息息：S->{},类名：{}", JSON.toJSON(msg),msg.getClass().getName());
        /**
         * 1.消息ID分类
         * 2.通过CMD字符串，或UserController指令 进一步细分
         */
        RtmpMsgHandler handler = statelessHandler.get(msgType);
        if(null != handler){
            handler.onMsg(msg);
        }else {
            log.warn("{} 没有实现处理",msg);
        }


//        switch (msgType){
//            case Constants.MSG_WINDOW_ACKNOWLEDGEMENT_SIZE:
//                WindowAcknowledgementSize ack= (WindowAcknowledgementSize) rtmpMessage;
//                break;
//            case Constants.MSG_SET_PEER_BANDWIDTH:
//                SetPeerBandwidth band= (SetPeerBandwidth) rtmpMessage;
//                break;
//            case Constants.MSG_TYPE_COMMAND_AMF0:
//                RtmpCommandMessage cmd= (RtmpCommandMessage) rtmpMessage;
//
//                break;
//        }
    }

    /**
     *

     * @param ctx
     * @param evt
     * @throws Exception
     */

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
       if(evt.equals("handlShake")){
           log.info("可以发送发送连接了");
           /**
            * 推、拉流都需要
            * connect
            *   等四个回复，win ack size|set bandwidth|set chunkSize  |_result()
            * releaseStream()
            * FCPublish()
            * createStream()
            *   等_result()
            *
            *
            *
            * publish()
            *   等onStatus()
            * @setDataFrame
            *
            */

           //发起连接
           RtmpCommandMessage conn=new RtmpCommandMessage();
           List<Object> connParam = new ArrayList<>();
           connParam.add("connect");
           connParam.add(1);//
           connParam.add(new Amf0Object()
                   .addProperty("app", "live")
                   .addProperty("type", "nonprivate")
                   .addProperty("flashVer","FMLE/3.0 (compatible; FMSc/1.0)")
                   .addProperty("swfUrl","rtmp://127.0.0.1/live")
                   .addProperty("tcUrl","rtmp://127.0.0.1/live")
                );// stream id
           conn.setCommand(connParam);
           ctx.writeAndFlush(conn);


       }
    }
}
